Imports vb = Microsoft.VisualBasic
Imports System.Threading

Public Class Form1



    ' Acceso al Nombre de Usuario del App
    Public Function UserName() As String
        On Error Resume Next
        UserName = Environment.UserName
    End Function

    Public TextoALeer As String = vbNullString
    Public Procedencia As String = vbNullString
    Public Mensaje As String = vbNullString


    Public Sub ActualizaDatos()
        On Error Resume Next

        ' Actualizamos el Texto de las Casillas Para Importar-lo al Hilo de Ejecución
        TextoALeer = TextBox1.Text
        Procedencia = TextBox2.Text
        If Len(TextoALeer) > 0 Then
            Mensaje = "Reading Number Chars: " & Len(TextoALeer) & Space(1) &
                      "Reading Number Words: " & TotalWordsCount(TextoALeer)
        Else
            Mensaje = vbNullString
        End If

    End Sub

    Public Sub CierraDatos()
        Mensaje = "Finalize Read"
    End Sub

    ' Este Método Será Llamado Por El Hilo de Ejecución
    Public Sub LeamosElTexto()

        ' Y Leemos el Texto
        TextToVoice(TextoALeer)

        ' Y Finalizamos la Lectura
        CierraDatos()

    End Sub

    ' API de Voz 
    Public Sub TextToVoice(ByVal TextForVoice As String)
        On Error Resume Next
        Dim SAPI As Object
        Dim Voces As Object
        SAPI = CreateObject("sapi.spvoice") ' Accedemos al objeto
        If Procedencia <> vbNullString Then
            ActualizaDatos()
            For Each Voces In SAPI.GetVoices
                If Strings.LCase(Procedencia) = Strings.LCase(Voces.GetDescription) Then
                    SAPI.Voice = Voces
                End If
            Next
        End If
        SAPI.Speak(TextForVoice) ' Leemos un Texto que se convierte a Voz
    End Sub

    ' Función de Guardado de un Archivo de Texto
    Public Function FileWriteData(ByVal FilePath As String, ByVal FileData As String) As Boolean
        On Error Resume Next
        Dim NumFile As Integer

        FileWriteData = False

        NumFile = vb.FileSystem.FreeFile
        vb.FileSystem.FileOpen(NumFile, FilePath, OpenMode.Binary, OpenAccess.Write, OpenShare.Shared)
        vb.FileSystem.FilePut(NumFile, FileData)
        vb.FileSystem.FileClose()

        If Err.Number = 0 Then
            FileWriteData = True
        End If

    End Function

    ' Funcion de Apertura de un Archivo de Texto
    Public Function FileReadData(ByVal FilePath As String) As String
        On Error Resume Next
        Dim NumFile As Integer, Datos As String, SubDatos As String
        Dim Man As Long, LenghtTempo As Long, LongitudSP As Integer

        FileReadData = vbNullString

        Datos = vbNullString

        NumFile = vb.FileSystem.FreeFile
        FileOpen(NumFile, FilePath, OpenMode.Binary, OpenAccess.Read, OpenShare.Shared)
        If Err.Number <> 0 Then Exit Function
        SubDatos = vbNullString
        LenghtTempo = LOF(NumFile)

        If LenghtTempo > 50000 Then
            For Man = 1 To LenghtTempo Step 50000
                LongitudSP = LenghtTempo - Man
                If LongitudSP < 50000 Then
                    Datos = Datos & Space(LongitudSP)
                    FileGet(NumFile, Datos)
                    SubDatos = SubDatos & Datos
                    Exit For
                Else
                    Datos = Datos & Space(50000)
                    FileGet(NumFile, Datos)
                    SubDatos = SubDatos & Datos
                End If
            Next
        Else
            Datos = Datos & Space(LenghtTempo)
            FileGet(NumFile, Datos)
            SubDatos = Datos
        End If

        FileReadData = SubDatos
        vb.FileSystem.FileClose()
    End Function

    ' Con esta Función Contaremos Palabras en el Texto
    Public Function WordsCount(ByVal TextString As String,
                  Optional ByVal WordString As String = vbNullString,
                  Optional ByVal EqualWord As Boolean = True) As Long
        On Error Resume Next
        WordsCount = 0
        If TextString = WordString Then WordsCount = 1 : Exit Function
        If TextString = vbNullString Then Exit Function
        If WordString = vbNullString Then
            ' Si no existe Palabra a Buscar es que se quiere Obtener el Numero de Palabras
            ' que contiene el Texto asi que salimos...
            Exit Function
        Else
            ' En Caso Contrario, Contamos las Palabras que sean Iguales que WordString
            ' Comprobamos si la Palabra Tiene que ser Exacta...
            If EqualWord = True Then
                ' Si tiene que ser Exacta
                If Len(TextString) =
                   Len(Replace(TextString, WordString, vbNullString)) Then Exit Function
                WordsCount =
                   Len(TextString) - ((Len(Replace(TextString, WordString, vbNullString, 1, -1, Microsoft.VisualBasic.CompareMethod.Binary)) \ Len(WordString)))
            Else
                ' Si No tiene que ser Exacta
                TextString = LCase(TextString)
                WordString = LCase(WordString)
                If Len(TextString) =
                   Len(Replace(TextString, WordString, vbNullString, 1, -1, Microsoft.VisualBasic.CompareMethod.Binary)) Then Exit Function
                WordsCount =
                   Len(TextString) - ((Len(Replace(TextString, WordString, vbNullString)) \ Len(WordString)))
            End If
        End If
    End Function

    ' Con esta Función Veremos Si Existe Cierta Palabra
    Public Function WordExist(ByVal TextString As String,
                              ByVal WordString As String,
                     Optional ByVal EqualWord As Boolean = True) As Boolean

        WordExist = False
        If WordsCount(TextString, WordString, EqualWord) > 0 Then WordExist = True
    End Function

    ' Con esta Función Contaremos Todas las Palabras de un Texto
    Public Function TotalWordsCount(ByVal TextString As String) As Long
        TotalWordsCount = 0
        If TextString <> vbNullString Then
            Return WordsCount(TextString, Space(1), True) + WordsCount(TextString, Chr(13), True) + 1
        Else
            Return 0
        End If

    End Function

    ' Cuando Cargamos el Formulario
    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load

        ' Cambiamos el Titulo de la Ventana
        Me.Text = "Text To Voice " & Application.ProductVersion

        'Buscamos todas las Voces Disponibles
        On Error Resume Next
        Dim SAPI As Object
        Dim Voces As Object
        SAPI = CreateObject("sapi.spvoice") ' Accedemos al objeto

        ' Y Cargamos todas las voces disponibles
        ListadoVoces.Items.Clear()
        For Each Voces In SAPI.GetVoices
            ListadoVoces.Items.Add(Voces.GetDescription)
        Next
        ListadoVoces.Text = ListadoVoces.Items(0)
        ListadoVoces_SelectedIndexChanged(Nothing, Nothing)

        Application.DoEvents()

        ' Activamos el Reloj Que Controla los Mensajes de Estado
        TiempoMensaje.Interval = 1000
        TiempoMensaje.Enabled = True
        TiempoMensaje.Start()

        ' Ponemos un texto a leer 
        If Strings.Right(ListadoVoces.Text, 7) = "(Spain)" Or
           Strings.Right(ListadoVoces.Text, 9) = "(Español)" Then
            TextBox1.Text = "Bienvenido " & UserName() & "." & vbCrLf &
                        "Soy Tu Asistente de Voz Personal." & vbCrLf &
                        "Escribe Aquí el Texto Que Quieres Que Lea."
        Else
            TextBox1.Text = "Welcome " & UserName() & "." & vbCrLf &
                        "I Am Your Personal Voice Assistant." & vbCrLf &
                        "Write Here The Text You Want Me To Read."
        End If

        ' Y Leemos el Texto con Voz 
        Dim MiHilo As Thread = New Thread(AddressOf LeamosElTexto)
        ActualizaDatos()
        MiHilo.Start()

    End Sub

    ' Cuando se Redimensiona la Ventana
    Private Sub Form1_Resize(sender As Object, e As EventArgs) Handles MyBase.Resize
        On Error Resume Next

        ' Movemos el Boton de Play
        Button1.Left = Me.ClientSize.Width - (Button1.Width + 5)
        Button1.Top = Me.ClientSize.Height - (Button1.Height + TextBox3.Height + 20)

        ' Movemos el Listado de Voces Instaladas
        ListadoVoces.Top = Button1.Top
        ListadoVoces.Width = Me.ClientSize.Width - (Button1.Width + 20)
        ListadoVoces.Left = Button1.Left - (ListadoVoces.Width + 10)


        ' Movemos el TextBox1 y le adaptamos el tamaño
        TextBox1.Left = 5
        TextBox1.Top = MenuSuperior.Top + MenuSuperior.Height + 5
        TextBox1.Width = Me.ClientSize.Width - 10
        TextBox1.Height = Button1.Top - (MenuSuperior.Top + MenuSuperior.Height + 10)

        ' Aquí Establecemos el Tamaño y Posición del TextBox2 aunque No es Visible 
        TextBox2.Top = ListadoVoces.Top + ListadoVoces.Height + 5
        TextBox2.Left = ListadoVoces.Left
        TextBox2.Width = ListadoVoces.Width

        ' Aquí Ponemos el Texto de la Información de Mensajes Que Controlan el Texto 
        TextBox3.Top = Me.ClientSize.Height - (TextBox3.Height + 5)
        TextBox3.Left = 5
        TextBox3.Width = Me.ClientSize.Width - 10

    End Sub



    ' Boton de Play
    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        On Error Resume Next

        ' Leemos el Texto
        Dim MiHilo As Thread = New Thread(AddressOf LeamosElTexto)
        ActualizaDatos()
        MiHilo.Start()

    End Sub

    ' Boton de Play en el Menu
    Private Sub MenuLeerTexto_Click(sender As Object, e As EventArgs) Handles MenuLeerTexto.Click
        On Error Resume Next

        ' Leemos el Texto
        Dim MiHilo As Thread = New Thread(AddressOf LeamosElTexto)
        ActualizaDatos()
        MiHilo.Start()

    End Sub

    ' Cuando pulsas el Menu Guardar Como
    Private Sub MenuGuardarComo_Click(sender As Object, e As EventArgs) Handles MenuGuardarComo.Click
        On Error Resume Next

        ' Asignamos el tipo de Archivo
        DialogoGuardar.Filter = "Archivo de Texto(.txt)|*.txt"

        ' Y si se acepta el cuadro de Guardado de Archivo 
        If DialogoGuardar.ShowDialog() = DialogResult.OK Then
            ' Y ademas lleba la extension
            If LCase(vb.Right(DialogoGuardar.FileName, 4)) = ".txt" Then
                ' Se Guarda el TextBox1 
                FileWriteData(DialogoGuardar.FileName, TextBox1.Text)
            Else
                ' Se Guarda el TextBox1 con extension txt
                FileWriteData(DialogoGuardar.FileName & ".txt", TextBox1.Text)
            End If
        End If

    End Sub

    ' Cuando Pulsas Abrir
    Private Sub MenuAbrir_Click(sender As Object, e As EventArgs) Handles MenuAbrir.Click
        On Error Resume Next

        ' Seteamos Propiedades 
        DialogoAbrir.Filter = "Archivo de Texto(.txt)|*.txt"
        DialogoAbrir.Multiselect = False

        ' Y si se acepta el cuadro de seleccion de archivo
        If DialogoAbrir.ShowDialog() = DialogResult.OK Then
            ' lo inserta en el TextBox1
            TextBox1.Text = FileReadData(DialogoAbrir.FileName)
        End If

    End Sub

    ' Cuando pulsas el Menu Guardar 
    Private Sub MenuGuardar_Click(sender As Object, e As EventArgs) Handles MenuGuardar.Click
        ' Llamamos a MenuGuardarComo
        MenuGuardarComo_Click(sender, e)

    End Sub

    ' Cuando Pulsas el Menu Copiar
    Private Sub CopiarToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles CopiarToolStripMenuItem.Click
        On Error Resume Next

        ' Copiamos al Portapapeles el contenido de TextBox1
        Clipboard.SetText(TextBox1.Text)

    End Sub

    ' Cuando Pulsas el Menu Pegar
    Private Sub MenuPegar_Click(sender As Object, e As EventArgs) Handles MenuPegar.Click
        On Error Resume Next

        ' Variable que recoge los Datos del Portapapeles 
        Dim Datos As String = vbNullString

        ' Si Hay Texto en el Portapapeles
        If Clipboard.ContainsText = True Then
            ' Lo Asignamos a Datos
            Datos = Clipboard.GetText
        End If

        ' Si hay texto en la variable Datos
        If Datos <> vbNullString Then
            ' Los ponemos en el TextBox1
            TextBox1.Text = Datos
        End If

    End Sub

    Private Sub ListadoVoces_SelectedIndexChanged(sender As Object, e As EventArgs) Handles ListadoVoces.SelectedIndexChanged
        On Error Resume Next

        TextBox2.Text = ListadoVoces.Text

    End Sub

    Private Sub TiempoMensaje_Tick(sender As Object, e As EventArgs) Handles TiempoMensaje.Tick
        On Error Resume Next
        Static Cuenta As Integer
        If TextBox3.Text <> Mensaje Then
            TextBox3.Text = Mensaje
        ElseIf Mensaje = "Finalize Read" Then
            If Cuenta >= 5 Then
                Cuenta = 0
                Mensaje = vbNullString
            Else
                Cuenta = Cuenta + 1
            End If
        ElseIf Mensaje = vbNullString Then
            If Cuenta >= 5 Then
                Cuenta = 0
                Mensaje = "Actually Number Chars: " & Len(TextBox1.Text) & Space(1) &
                      "Actually Number Words: " & TotalWordsCount(TextBox1.Text)
            Else
                Cuenta = Cuenta + 1
            End If
        End If
    End Sub

    Private Sub TextBox1_TextChanged(sender As Object, e As EventArgs) Handles TextBox1.TextChanged
        On Error Resume Next

        Mensaje = "Writing Number Chars: " & Len(TextBox1.Text) & Space(1) &
                      "Writing Number Words: " & TotalWordsCount(TextBox1.Text)

    End Sub

    Private Sub MenuAcercaDeTextToVoiceItem_Click(sender As Object, e As EventArgs) Handles MenuAcercaDeTextToVoiceItem.Click
        On Error Resume Next

        Dim AcercaDe As New AboutBox1
        AcercaDe.ShowDialog()
        AcercaDe.Close()

    End Sub
End Class
